﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Configuration;
using System.Net.Http;
using System.Runtime.Caching;
using System.Threading;
using System.Web.Http;
using DisconfClient;
using Newtonsoft.Json;
using Ymatou.CommonService;
using Ymatou.PerfMonitorClient;
using Ymatou.ServiceCenter.Common;
using Ymatou.ServiceCenter.Common.Extensions;
using Ymatou.ServiceCenter.Domain;
using Ymatou.ServiceCenter.Domain.Models;
using Ymatou.ServiceCenter.WebApi.Utility;

namespace Ymatou.ServiceCenter.WebApi.Controllers
{
    [RoutePrefix("api/Service")]
    public class ServiceController : ApiController
    {
        [HttpPost]
        [Route("Test")]
        public string Test(string request)
        {
            return "ok";
        }

        [HttpPost]
        [Route("SaveServicedependency_Info")]
        public void SaveServicedependency_Info(ServiceDependencySampling samplings)
        {
            if (samplings == null) return;
            ApplicationLog.Debug(string.Format("[SaveServicedependencyInfo] 接到服务 {0} 依赖 {1} 数据",
                samplings.ConsumerAppId, samplings.ProviderAppId));

            try
            {
                var dependency =
                RepositoryHub.ServicedependencyInfoRepository.GetById(new { ConsumerAppId = samplings.ConsumerAppId, ProviderAppId = samplings.ProviderAppId });
                if (dependency != null)
                {
                    dependency.LastUpdateTime = DateTime.Now;
                    var result = RepositoryHub.ServicedependencyInfoRepository.Update(dependency);
                    ApplicationLog.Debug(string.Format("[SaveServicedependencyInfo] 服务 {0} 依赖 {1} 数据成功更新,{2}",
                        samplings.ConsumerAppId, samplings.ProviderAppId, result));
                }
                else
                {
                    dependency = new ServicedependencyInfo
                    {
                        ConsumerAppId = samplings.ConsumerAppId,
                        ProviderAppId = samplings.ProviderAppId,
                        CreateTime = DateTime.Now,
                        LastUpdateTime = DateTime.Now
                    };
                    var result = RepositoryHub.ServicedependencyInfoRepository.Insert(dependency);
                    ApplicationLog.Debug(string.Format("[SaveServicedependencyInfo] 服务 {0} 依赖 {1} 数据成功添加,{2}",
                        samplings.ConsumerAppId, samplings.ProviderAppId, result));
                }
            }catch(Exception ex)
            {
                ApplicationLog.Error(string.Format("[SaveServicedependencyInfo]异常：{0}", ex.Message), ex);
            }
        }

        [HttpGet]
        [Route("GetRpcClientCfg/{appId}")]
        public RpcClientConfig GetRpcClientCfg(string appId)
        {
            if (string.IsNullOrEmpty(appId)) return RpcClientConfig.DefaultRpcClientConfig;
            string key =  string.Format("GetRpcClientCfg-{0}", appId);
            return MemoryCache.Default.Get<RpcClientConfig>(key, new TimeSpan(0, 3, 0), () => GetRpcClientCfgFromDb(appId),true);
        }

        private RpcClientConfig GetRpcClientCfgFromDb(string appId)
        {
            if (string.IsNullOrEmpty(appId)) return RpcClientConfig.DefaultRpcClientConfig;
            var cfg = RepositoryHub.RpcClientConfigRepository.FindByAppId(appId);
            if (cfg == null) return RpcClientConfig.DefaultRpcClientConfig;
            return cfg;
        }

        

        [HttpGet]
        [Route("GetAllAppIdList")]
        public IList<string> GetAllAppIdList()
        {
            return RepositoryHub.ServiceMetadataRepository.GetAllAppIdList();
        }

        [HttpGet]
        [Route("GetServiceMetadatas")]
        public IList<ServiceMetadata> GetServiceMetadatas(string appId, long? lastUpdateTicks)
        {
            if (string.IsNullOrWhiteSpace(appId))
                return null;
            using (MethodMonitor.New(string.Format("GetServiceMetadatas({0})", appId)))
            {
                string key = string.Format("GetServiceMetadatas,{0},{1}", appId, lastUpdateTicks);
                return MemoryCache.Default.Get<IList<ServiceMetadata>>(key, new TimeSpan(0, 3, 0),
                    () => RepositoryHub.ServiceMetadataRepository.GetServiceMetadatas(appId, lastUpdateTicks), true);
//            return RepositoryHub.ServiceMetadataRepository.GetServiceMetadatas(appId, lastUpdateTicks);
            }
        }

        [HttpGet]
        [Route("GetServiceMetadata")]
        public ServiceMetadata GetServiceMetadata(string appId, string apiName, string httpMethod)
        {
            return RepositoryHub.ServiceMetadataRepository.GetServiceMetadata(appId, apiName, httpMethod);
        }

        [HttpPost]
        [Route("SaveServiceMetadata")]
        public void SaveServiceMetadata(ServiceMetadata serviceMetadata)
        {
            if (serviceMetadata == null)
                return;
            try
            {
                ApplicationLog.Debug(string.Format("[SaveServiceMetadata] 接到 {0} 服务元数据数据", serviceMetadata.AppId));
                ServiceMetadata getServiceMetadata = RepositoryHub.ServiceMetadataRepository.GetServiceMetadata(serviceMetadata.AppId, serviceMetadata.ApiName, serviceMetadata.HttpMethod);
                if (getServiceMetadata == null)
                {
                    bool flag =  RepositoryHub.ServiceMetadataRepository.Insert(serviceMetadata);
                    ApplicationLog.Debug(string.Format("[SaveServiceMetadata]AppId:{0}, ApiName:{1},HttpMethod:{2},Insert:{3}",
                            serviceMetadata.AppId, serviceMetadata.ApiName, serviceMetadata.HttpMethod, flag));
                }
                else
                {
                    bool flag = RepositoryHub.ServiceMetadataRepository.Update(serviceMetadata);
                    ApplicationLog.Debug(string.Format("[SaveServiceMetadata]AppId:{0}, ApiName:{1},HttpMethod:{2},Update:{3}",
                            serviceMetadata.AppId, serviceMetadata.ApiName, serviceMetadata.HttpMethod, flag));
                }
            }
            catch (Exception ex)
            {
                ApplicationLog.Error(string.Format("[SaveServiceMetadata]AppId:{0}, ApiName:{1},HttpMethod:{2},保存数据异常。",
                              serviceMetadata.AppId, serviceMetadata.ApiName, serviceMetadata.HttpMethod), ex);           
            }

        }

        [HttpPost]
        [Route("SaveServiceMetadatas")]
        public void SaveServiceMetadatas(IList<ServiceMetadata> serviceMetadatas)
        {
            if (serviceMetadatas == null || serviceMetadatas.Count <= 0)
                return;

            foreach (ServiceMetadata serviceMetadata in serviceMetadatas)
            {
                DateTime now = DateTime.Now;
                try
                {
                    var tmpServiceMetadata =
                       RepositoryHub.ServiceMetadataRepository.GetServiceMetadata(serviceMetadata.AppId,
                           serviceMetadata.ApiName, serviceMetadata.HttpMethod);
                    if (tmpServiceMetadata==null)
                    {
                        serviceMetadata.CreateTime = now;
                        serviceMetadata.LastUpdateTime = now;
                        serviceMetadata.LastUpdateTicks = now.Ticks;
                        bool flag = RepositoryHub.ServiceMetadataRepository.Insert(serviceMetadata);
                        ApplicationLog.Debug(string.Format("[SaveServiceMetadatas]AppId:{0}, ApiName:{1},HttpMethod:{2},Insert:{3}",
                               serviceMetadata.AppId, serviceMetadata.ApiName, serviceMetadata.HttpMethod, flag));
                    }
                }
                catch (Exception ex)
                {
                    ApplicationLog.Error(string.Format("[SaveServiceMetadatas]AppId:{0}, ApiName:{1},HttpMethod:{2},保存数据异常。",
                              serviceMetadata.AppId, serviceMetadata.ApiName, serviceMetadata.HttpMethod), ex);                     
                }
            }
        }

        [HttpGet]
        [Route("MyProviderList")]
        public IList<ServiceDependency> MyProviderList(string appId)
        {
            return RepositoryHub.ServiceDependencyRepository.MyProviderList(appId);
        }

        [HttpGet]
        [Route("MyConsumerList")]
        public IList<ServiceDependency> MyConsumerList(string appId)
        {
            return RepositoryHub.ServiceDependencyRepository.MyConsumerList(appId);
        }

        [HttpPost]
        [Route("SaveServiceDependencySamplings")]
        public void SaveServiceDependencySamplings(IList<ServiceDependencySampling> samplings)
        {
            if (samplings == null || samplings.Count<=0)
                return;
            bool isIgnoreSampling = ConfigManager.GetConfigValue<bool>("IsIgnoreSampling");
            if(isIgnoreSampling)
                return;

            bool isMergeSampling = ConfigManager.GetConfigValue<bool>("IsMergeSampling",true);
            Dictionary<string, ServiceDependencySampling> dictionary =
                    new Dictionary<string, ServiceDependencySampling>();
            if (isMergeSampling)
            {
                foreach (ServiceDependencySampling sampling in samplings)
                {
                    if (sampling == null)
                        continue;
                    try
                    {
                        string key = string.Format("{0},{1},{2}", sampling.ConsumerAppId, sampling.ProviderAppId,
                            sampling.ApiPath);
                        if (!dictionary.ContainsKey(key))
                        {
                            ServiceDependencySampling serviceDependencySampling = sampling;
                            serviceDependencySampling.ApiName = "";
                            dictionary.Add(key, serviceDependencySampling);
                        }
                        else
                        {
                            ServiceDependencySampling getSampling = dictionary[key];
                            if (getSampling == null)
                                continue;
                            getSampling.MaxElapsedTime = Math.Max(getSampling.MaxElapsedTime, sampling.MaxElapsedTime);
                            getSampling.MinElapsedTime = Math.Min(getSampling.MinElapsedTime, sampling.MinElapsedTime);
                            if (sampling.BeginTime < getSampling.BeginTime)
                                getSampling.BeginTime = sampling.BeginTime;

                            if (sampling.EndTime > getSampling.EndTime)
                                getSampling.EndTime = sampling.EndTime;

                            getSampling.SamplingElapsedSeconds =
                                (long) (getSampling.EndTime - getSampling.BeginTime).TotalSeconds;
                            getSampling.TotalFailTimes += sampling.TotalFailTimes;
                            getSampling.TotalRequestTimes += sampling.TotalRequestTimes;
                            getSampling.TotalRequestElapsedMilliseconds += sampling.TotalRequestElapsedMilliseconds;
                            getSampling.ApiName = "";
                            dictionary[key] = getSampling;
                        }
                    }
                    catch (Exception ex)
                    {
                        ApplicationLog.Warn("[SaveServiceDependencySamplings]," + ex.ToString());
                    }

                }
            }

            ApplicationLog.Debug("[SaveServiceDependencySamplings] 开始写入服务依赖采样数据");
            int result = RepositoryHub.ServiceDependencySamplingRepository.TryInsert(isMergeSampling ? dictionary.Values.ToList() : samplings);
            ApplicationLog.Debug(string.Format("[SaveServiceDependencySamplings] {0} 条服务依赖采样数据，成功写入", result));
        }

        [HttpGet]
        [Route("GetSamplingStatistics")]
        public SamplingStatistics GetSamplingStatistics(string consumerAppId, string providerAppId, DateTime beginTime, DateTime endTime)
        {
            SamplingStatistics statistics = new SamplingStatistics();
            ServiceDependencySampling sampling = RepositoryHub.ServiceDependencySamplingRepository.GetServiceDependencySampling(consumerAppId, providerAppId, beginTime, endTime);
            if (sampling == null)
                return null;
            statistics.TotalRequestTimes = sampling.TotalRequestTimes;
            statistics.TotalFailTimes = sampling.TotalFailTimes;
            statistics.RequestsPerSecond = (int)(sampling.TotalRequestTimes / sampling.SamplingElapsedSeconds);
            statistics.TimePerRequest = (int)(sampling.TotalRequestElapsedMilliseconds / sampling.TotalRequestTimes);
            return statistics;
        }

        [HttpGet]
        [Route("GetServiceConfig")]
        public ServiceConfig GetServiceConfig(string consumerAppId, string providerAppId)
        {
            string key = string.Format("GetServiceConfig-{0},{1}", consumerAppId, providerAppId);
            return MemoryCache.Default.Get<ServiceConfig>(key, new TimeSpan(0, 3, 0), () => RepositoryHub.ServiceConfigRepository.GetServiceConfig(consumerAppId, providerAppId),true);
            //return RepositoryHub.ServiceConfigRepository.GetServiceConfig(consumerAppId, providerAppId);
        }

        [HttpPost]
        [Route("SaveServiceConfig")]
        public void SaveServiceConfig(ServiceConfig serviceConfig)
        {
            if(serviceConfig==null)
                return;
            try
            {
                ServiceConfig config = RepositoryHub.ServiceConfigRepository.GetServiceConfig(serviceConfig.ConsumerAppId,
    serviceConfig.ProviderAppId);
                if (config == null)
                {
                    bool flag = RepositoryHub.ServiceConfigRepository.Insert(serviceConfig);
                    ApplicationLog.Debug(string.Format("[SaveServiceConfig]ConsumerAppId:{0}, ProviderAppId:{1},IsDisabled:{2},Insert:{3}",
                               serviceConfig.ConsumerAppId, serviceConfig.ProviderAppId, serviceConfig.IsDisabled, flag));
                }
                else
                {
                    bool flag = RepositoryHub.ServiceConfigRepository.Update(serviceConfig);
                    ApplicationLog.Debug(string.Format("[SaveServiceConfig]ConsumerAppId:{0}, ProviderAppId:{1},IsDisabled:{2},Update:{3}",
                              serviceConfig.ConsumerAppId, serviceConfig.ProviderAppId, serviceConfig.IsDisabled, flag));
                }
            }
            catch (Exception ex)
            {
                ApplicationLog.Error(string.Format("[SaveServiceConfig]ConsumerAppId:{0}, ProviderAppId:{1},IsDisabled:{2},保存失败。",
                              serviceConfig.ConsumerAppId, serviceConfig.ProviderAppId, serviceConfig.IsDisabled),ex);
            }

            
        }

        [HttpGet]
        [Route("GetServiceConfigByConsumerAppId")]
        public IList<ServiceConfig> GetServiceConfigByConsumerAppId(string consumerAppId)
        {
            if (string.IsNullOrWhiteSpace(consumerAppId))
                return null;

            return RepositoryHub.ServiceConfigRepository.GetServiceConfigByConsumerAppId(consumerAppId);
        }

        [HttpGet]
        [Route("GetServiceConfigByProviderAppId")]
        public IList<ServiceConfig> GetServiceConfigByProviderAppId(string providerAppId)
        {
            if (string.IsNullOrWhiteSpace(providerAppId))
                return null;
            return RepositoryHub.ServiceConfigRepository.GetServiceConfigByProviderAppId(providerAppId);
        }

        [HttpGet]
        [Route("GetServiceConfigs")]
        public IList<ServiceConfig> GetServiceConfigs(string appId, long? lastUpdateTicks)
        {
            if (string.IsNullOrWhiteSpace(appId))
                return null;
            using (MethodMonitor.New(string.Format("GetServiceConfigs({0})",appId)))
            {
                string key = string.Format("GetServiceConfigs-{0}-{1}", appId, lastUpdateTicks);
                return MemoryCache.Default.Get<IList<ServiceConfig>>(key, new TimeSpan(0, 3, 0),
                    () => RepositoryHub.ServiceConfigRepository.GetServiceConfigs(appId, lastUpdateTicks), true);
            }
            //return RepositoryHub.ServiceConfigRepository.GetServiceConfigs(appId, lastUpdateTicks);
        }

     
    }
}


public class SamplingStatistics
{
    /// <summary>
    /// 平均每秒请求数
    /// </summary>
    public int RequestsPerSecond { get; set; }

    /// <summary>
    /// 每次请求平均耗时
    /// </summary>
    public int TimePerRequest { get; set; }

    /// <summary>
    /// 采样时间段内总接口请求数
    /// </summary>
    public long TotalRequestTimes { get; set; }

    /// <summary>
    /// 采样时间段内总接口请求失败数
    /// </summary>
    public long TotalFailTimes { get; set; }
}